unsigned long nextIrrigationTime = 0;
int irrigationDelayHours = 8;
int targetSoilMoisture = 600;
int photoCellReading = 0;
int moistureSensorReading = 0;
int batteryReading = 0;
int MAX_PHOTO_VALUE = 600;
int MIN_PHOTO_VALUE = 800;

//Analog input pins
int batteryPin = A0;
int moistureSensorPin = A1;
int temperature = A2
int photoCellPin = A3;

//Digital control pins
int solenoidControlPinA = 2;
int solenoidControlPinB = 3;

char messageBuffer[20];
int messageBufferIndex;

typedef enum { WATER_IDLE, WATER_FLOWING } irrigationState;

irrigationState currentIrrigationState = WATER_IDLE;

boolean correctLighting(void);
boolean correctMoisture(void);
boolean cycleDelayElapsed(void);
void startIrrigationCycle(void);
void checkEndOfCycle(void);
void processSerialInput( void );
void processCommand( void );

void setup()
{
  pinMode(OUTPUT, solenoidControlPin);
  pinMode(OUTPUT, redLED);
  pinMode(OUTPUT, yellowLED);
  digitalWrite(solenoidControlPin, LOW);
  digitalWrite(redLED, LOW);
  digitalWrite(yellowLED, LOW);
  Serial.begin(9600);
}

void loop()
{
  if ( correctLighting() && !correctMoisture() && cycleDelayElapsed() )
  {
    if ( currentIrrigationState == WATER_IDLE )
    {
      startIrrigationCycle();
    }
  }
  if ( currentIrrigationState == WATER_FLOWING )
  {
    checkEndOfCycle();
  }
  processSerialInput();
}

void processSerialInput( void )
{
  char inByte;
  char startCharacter = '$';
  char closeCharacter = '|';
  if ( Serial.available() > 0 )
  {
    inByte = Serial.read();
    if ( inByte == startCharacter )
    {
      messageBufferIndex = 0;
    }
    else if ( inByte == closeCharacter )
    {
      processCommand();
    }
    else
    {
      messageBuffer[messageBufferIndex] = inByte;
      messageBufferIndex++;
    }
  }
}

boolean cycleDelayElapsed( void )
{
  unsigned long currentTime = millis();
  if ( currentTime > nextIrrigationTime )
  {
    return true;
  }
  return false;
}

void checkEndOfCycle(void)
{
  if ( correctMoisture() )
  {
    digitalWrite(solenoidControlPin, LOW);
    digitalWrite(redLED, HIGH);
    currentIrrigationState == WATER_IDLE;
  }
}
    

boolean correctLighting(void)
{
  photoCellReading = analogRead( photoCellPin );
  if ( photoCellReading > MIN_PHOTO_VALUE && photoCellReading < MAX_PHOTO_VALUE )
  {
    return true;
  }
  return false;
}

boolean correctMoisture(void)
{
  moistureSensorReading = analogRead( moistureSensorPin );
  if ( moistureSensorReading > targetSoilMoisture )
  {
    return true;
  }
  return false;
}

void startIrrigationCycle(void)
{
  digitalWrite(solenoidControlPin, HIGH);
  digitalWrite(redLED, HIGH);
  currentIrrigationState = WATER_FLOWING;
  nextIrrigationTime = millis() + (irrigationDelayHours * 60 * 60 * 1000);
}

void processCommand( void )
{
  char commandType = messageBuffer[0];
  int MSB;
  int LSB;
  Serial.write(0);
  switch ( commandType )
  {
    case 'A':
      //send back all data
      if ( currentIrrigationState == WATER_IDLE )
      {
        Serial.write(0);
      }
      else
      {
        Serial.write(1);
      }
      moistureSensorReading = analogRead( moistureSensorPin );
      MSB = moistureSensorReading >> 8;
      LSB = moistureSensorReading & 0x00FF;
      Serial.write(MSB);
      Serial.write(LSB);
      photoCellReading = analogRead( photoCellPin );
      MSB = photoCellReading >> 8;
      LSB = photoCellReading & 0x00FF;
      Serial.write(MSB);
      Serial.write(LSB);
      batteryReading = analogRead ( batteryPin );
      MSB = batteryReading >> 8;
      LSB = batteryPin & 0x00FF;
      Serial.write(MSB);
      Serial.write(LSB);
      break;
  }
}
